using System.Diagnostics;
using System.Drawing;
using System.Drawing.Imaging;
using AutoClick.native;
using AutoClick.utils;
using SharpDX;
using SharpDX.Direct3D11;
using SharpDX.DXGI;
using Buffer = System.Buffer;
using Device = SharpDX.Direct3D11.Device;
using MapFlags = SharpDX.Direct3D11.MapFlags;
using ResultCode = SharpDX.DXGI.ResultCode;

namespace AutoClick.capture.impl
{
    public class DxgiCapture : IGameCapture, IDisposable
    {
        private static DxgiCapture? _instance;
        public static DxgiCapture Instance => _instance ??= new DxgiCapture();

        // DXGI资源
        private Factory1? _factory;
        private Adapter1? _adapter;
        private Device? _device;
        private Output1? _output;
        private OutputDuplication? _duplication;

        // 复用纹理
        private Texture2D? _stagingTexture;
        private Texture2DDescription _lastDesc;

        private DxgiCapture()
        {
            Dispose();
            InitializeDxgi();
        }

        private void InitializeDxgi()
        {
            // 初始化DXGI 1.2
            _factory = new Factory1();
            _adapter = _factory.GetAdapter1(0);
            _device = new Device(_adapter, DeviceCreationFlags.BgraSupport);

            // 获取主显示器输出
            var output = _adapter.GetOutput(0);
            _output = output.QueryInterface<Output1>();

            // 创建桌面复制接口
            _duplication = _output.DuplicateOutput(_device);
        }

        public Bitmap? Capture(IntPtr hWnd)
        {
            var stopWatch = Stopwatch.StartNew();

            try
            {
                // 获取窗口区域（与原类兼容）
                User32.GetWindowRect(hWnd, out Rect rect);
                var width = rect.Right - rect.Left;
                var height = rect.Bottom - rect.Top;

                // 捕获当前帧
                var result = _duplication!.TryAcquireNextFrame(50, out _, out var resource);
                if (result.Failure)
                {
                    if (result.Code == ResultCode.WaitTimeout.Code) return null;
                    throw new SharpDXException(result);
                }

                using var texture = resource.QueryInterface<Texture2D>();
                // 准备兼容的暂存纹理
                PrepareStagingTexture(texture.Description);

                // 复制到CPU可访问的纹理
                _device!.ImmediateContext.CopyResource(texture, _stagingTexture);

                // 映射显存
                var dataBox = _device!.ImmediateContext.MapSubresource(
                    _stagingTexture, 0, MapMode.Read, MapFlags.None);

                try
                {
                    // 创建Bitmap并复制数据
                    var bitmap = new Bitmap(width, height, PixelFormat.Format32bppArgb);
                    var bounds = new Rectangle(0, 0, width, height);
                    var bitmapData = bitmap.LockBits(bounds, ImageLockMode.WriteOnly, bitmap.PixelFormat);

                    unsafe
                    {
                        var srcPtr = (byte*)dataBox.DataPointer;
                        var dstPtr = (byte*)bitmapData.Scan0;

                        // 窗口在屏幕中的起始偏移
                        var startX = rect.Left;
                        var startY = rect.Top;

                        // 按行拷贝（处理内存对齐差异）
                        for (var y = 0; y < height; y++)
                        {
                            Buffer.MemoryCopy(
                                srcPtr + (startY + y) * dataBox.RowPitch + startX * 4,
                                dstPtr + y * bitmapData.Stride,
                                width * 4,
                                width * 4
                            );
                        }
                    }

                    bitmap.UnlockBits(bitmapData);
                    stopWatch.Stop();
                    Console.WriteLine($"DXGI Capture Time: {stopWatch.ElapsedMilliseconds}ms");
                    return bitmap;
                }
                finally
                {
                    _device.ImmediateContext.UnmapSubresource(_stagingTexture, 0);
                }
            }
            finally
            {
                _duplication?.ReleaseFrame();
            }
        }

        private void PrepareStagingTexture(Texture2DDescription desc)
        {
            if (desc.Width == _lastDesc.Width &&
                desc.Height == _lastDesc.Height) return;

            _stagingTexture?.Dispose();

            var stagingDesc = new Texture2DDescription
            {
                Width = desc.Width,
                Height = desc.Height,
                MipLevels = 1,
                ArraySize = 1,
                Format = Format.B8G8R8A8_UNorm,
                SampleDescription = new SampleDescription(1, 0),
                Usage = ResourceUsage.Staging,
                BindFlags = BindFlags.None,
                CpuAccessFlags = CpuAccessFlags.Read,
                OptionFlags = ResourceOptionFlags.None
            };

            _stagingTexture = new Texture2D(_device, stagingDesc);
            _lastDesc = desc;
        }

        public void Dispose()
        {
            // 按反向顺序释放（关键！）
            _duplication?.Dispose();
            _output?.Dispose();
            _device?.Dispose();
            _adapter?.Dispose();
            _factory?.Dispose();
            _stagingTexture?.Dispose();

            // 重置为null防止残留
            _duplication = null;
            _output = null;
            _device = null;
            _adapter = null;
            _factory = null;
            _stagingTexture = null;
        }
    }
}